package org.mashart.pink.m.store;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Calendar;
import javax.microedition.io.file.*;
import javax.microedition.io.Connector;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.InvalidRecordIDException;
import javax.microedition.rms.RecordEnumeration;
/**
 * FileManager. Save the file on mobile device.
 */
public class FileManager {
    private static FileManager unique;

    /**
     * name of the folder
     */
//    private String folderName;

    /**
     * File path
     */
    public String path;

    /**
     * string representing the date
     */
    private String strDate;

    /**
     * Extensive name
     */
    private String ext;

    /**
     * Serial Number of data file
     */
    private int sn;

    private FileManager(){
        // set folder name, under which pinkr will save the GPS data file
//        folderName = "pinkr/";
        // set extensive name of the file
        ext = ".dat";
    }

    /**
     * Factory method
     * @return a unique instance of <code>RecordManager</code>.
     */
    public static synchronized FileManager getInstance(){
        if(unique == null){
            unique = new FileManager();
        }
        return unique;
    }

    public int initialize(){
        // if the path is not set yet, use the prefered path
        if( path == null ){
            setPath( getPreferedPath() );
        }
        // make directory if it does not exist yet
        mkdir();
        // look up the current existed data files, and initialze the current serial number
        initializeSerialNumber();
//        path = getPreferedPath();
//        return path != null ? 1 : -1;
        return 1;
    }

    /**
     * Check if the File API (JSR 75) is available.
     * @return
     */
    public static boolean isAPIAvailable(){
        return System.getProperty("microedition.io.file.FileConnection.version") != null;
    }

    /**
     * Get the prefered root for data file
     */
    public static String getPreferedPath(){
        // search for some prefered root driver name
        // define some prefered root name, the order represent the preference. More prefer <-> less prefer.
        String [] preferedRoots = { "Memory card/", "E:/", "Phone memory/", "C:/" };
        // search the prefered root name
        for(int i = 0; i < preferedRoots.length; i++){
            Enumeration e = FileSystemRegistry.listRoots();
            while (e.hasMoreElements()) {
                String root = (String) e.nextElement();
                // whenever one prefered root name is found, use it and return
                if(root.equals(preferedRoots[i])){
                    return "file:///" + root + "pinkr/";
                }
            }
        }

        // program reaches here means not a prefered root is found, then use the first root, if any
        Enumeration e = FileSystemRegistry.listRoots();
        if(e.hasMoreElements()){
            String root = (String) e.nextElement();
            return "file:///" + root + "pinkr/";
        }else{
            // there is not any root driver, should not happen if the File API is available on this mobile device
            return null;
        }
    }

    /**
     * set the path
     */
    public void setPath(String p){
        path = p;
    }

    /**
     * Create the directory, under which pinkr will save the file.
     * If the directory already exists, do nothing.
     */
    public int mkdir(){
        FileConnection conn = null;

        try {
            conn = (FileConnection) Connector.open( path, Connector.READ_WRITE );
            // if the pinkr directory does not exist, create one
            if(!conn.exists()){
                conn.mkdir();
            }
            conn.close();
            return 1;
        }
        catch( IOException e ){
            // could not access the URL
            e.printStackTrace();
            return -1;
        }
        catch( SecurityException e ){
            // no permission to read the directory
            e.printStackTrace();
            return -1;
        }
    }
    
    /**
     * get the string representing the date
     */
    private String getDateString(){
        // get the year, month, date
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int date = cal.get(Calendar.DATE);

        StringBuffer fn = new StringBuffer();
        fn.append(year);
        if(month < 10){ fn.append('0'); }
        fn.append(month);
        if(date < 10){ fn.append('0'); }
        fn.append(date);
        return fn.toString();
    }

    /**
     * initialize the serial number
     *
     */
    public void initializeSerialNumber(){
        String res = null;
        // length of a name, 8 digits for date, 3 digits for serial number
        int len = 8 + 3 + ext.length();

        // get the string representing the date
        String sd = getDateString();
        StringBuffer fn = new StringBuffer( sd );

        // serial number
        int n = 0;
        // get the greatest serial number, which has been used today
        FileConnection conn = null;
        try {
            conn = (FileConnection) Connector.open( path, Connector.READ );
//            if( conn.isDirectory() ){
                // filter the file names, which represent today
                Enumeration names = conn.list( fn.toString() + "*" + ext, true );
                while( names.hasMoreElements() ){
                    String name = (String) names.nextElement();
                    // the serial number is expected less than 999, if it grow greater than 999
                    // the length becomes longer than 11, still works, though not nice.
                    if(name.length() >= len){
                        // get the suffix from 9th digits.
                        String suffix = name.substring(8, name.length() - ext.length());
                        try{
                            int t = Integer.parseInt(suffix);
                            if(n < t){
                                n = t;
                            }
                        }catch(NumberFormatException e){
                            // suffix is not a number, should not happen
                        }
                    }
                }
                conn.close();
                // set serial number
                sn = n;
                // set the date string
                strDate = sd;
        }
        catch( IOException e ){
            // could not access the URL
            e.printStackTrace();
        }
        catch( SecurityException e ){
            // no permission to read the directory
            e.printStackTrace();
        }
    }

    /**
     * Generate a file name for a new file. The file name pattern is 8 digits date
     * plus 3 digits serial number for that day, e.g., 20090416001.
     * 
     */
    public String generateFileName(){
        String res = null;
        
        // get the string representing the date
        StringBuffer fn = new StringBuffer();
        fn.append(strDate);

        // new serial number = "greatest serial number used" + 1
        sn++;
        if(sn < 100){ fn.append('0'); }
        if(sn < 10){ fn.append('0'); }
        fn.append(sn);
        res = fn.toString();
        return res;
    }

    /**
     * Save a RecordStore into a file.
     * @param fileName
     * @param RecordManager, should be open already
     * @return
     */
    public int save(RecordManager rm){
        int res;
        // generate a file name
        String fileName = generateFileName();
        FileConnection conn = null;
        try {
            conn = (FileConnection) Connector.open( path + fileName + ext, Connector.WRITE );
            // create the file
            conn.create();
            // a file with the same name should not exist up to now
            OutputStream ostream = conn.openOutputStream();

            rm.writeOutputStream(ostream);

            // close output stream
            ostream.close();
            // close file
            conn.close();
            res = 1;
        }
        catch( IOException e ){
            // could not access the URL
            e.printStackTrace();
            res = -1;
        }
        catch( SecurityException e ){
            // no permission to read the directory
            e.printStackTrace();
            res = -1;
        }
        return res;
    }

    /**
     * Save a RecordStore into a file.
     * @param fileName
     * @param RecordManager, should be open already
     * @return
     */
    public int save(RecordStore rs){
        int res = 1;
        // generate a file name
        String fileName = generateFileName();
        FileConnection conn = null;
        try {
            conn = (FileConnection) Connector.open( path + fileName + ext, Connector.WRITE );
            // create the file
            conn.create();
            // a file with the same name should not exist up to now
            OutputStream ostream = conn.openOutputStream();

            RecordEnumeration re;
            try{
                re = rs.enumerateRecords(null, null, false);
                while(re.hasNextElement()){
                    byte[] b = re.nextRecord();
                    // write the bytes into the output stream
                    try{
                        ostream.write(b);
                        ostream.write('\n');
                    }catch(IOException e){
                        e.printStackTrace();
                        res = -1;
                    }
                }
            }catch(RecordStoreException rse){
                rse.printStackTrace();
                res = -1;
            }

            // close output stream
            ostream.close();
            // close file
            conn.close();
        }
        catch( IOException e ){
            // could not access the URL
            e.printStackTrace();
            res = -1;
        }
        catch( SecurityException e ){
            // no permission to read the directory
            e.printStackTrace();
            res = -1;
        }
        return res;
    }

    public int save(byte[] b){
        int res;
        // generate a file name
        String fileName = generateFileName();
        FileConnection conn = null;
        try {
            conn = (FileConnection) Connector.open( path + fileName + ext, Connector.WRITE );
            // create the file
            conn.create();
            // a file with the same name should not exist up to now
            OutputStream ostream = conn.openOutputStream();

            ostream.write(b);

            // close output stream
            ostream.close();
            // close file
            conn.close();
            res = 1;
        }
        catch( IOException e ){
            // could not access the URL
            e.printStackTrace();
            res = -1;
        }
        catch( SecurityException e ){
            // no permission to read the directory
            e.printStackTrace();
            res = -1;
        }
        return res;
    }
}
